AlarmManager实质上是一个全局定时器,是Android中常用的一种系统服务级别的提示服务,在指定时间或周期性启动其他组件(Activity、Service、BroadcastReceiver)。
之前有篇文章专门介绍了AlarmManager定时器的使用方法,获取到服务后,调用该服务的一些设置方法,在设定时间到达后就会启动指定的组件。
AlarmManagerService和JobSchedulerService一样都是系统服务,故它们的启动流程也类似,先看下时序图:
Zygote进程启动后会启动System进程,在System进程启动过程中会启动系统中的关键服务,如AMS、PMS、JobSchedulerService以及这里要分析的AlarmManagerService。
SystemServer启动AlarmManagerService服务调用的是SystemServiceManager类的startService方法:
private void startOtherServices() {
try {
. . .
mSystemServiceManager.startService(AlarmManagerService.class);
. . .
} catch (RuntimeException e) {
Slog.e("System", "******************************************");
Slog.e("System", "************ Failure starting core service", e);
}
}
SystemServiceManager类的startService方法在JobSchedulerService的分析中已经分析过,这里粘贴写代码:
private final ArrayList<SystemService> mServices = new ArrayList<SystemService>();
/**
* 创建并启动一个继承自SystemService类的系统服务。
*
* @param 一个继承自SystemService类的服务类
* @return 服务类的实例
* @throws 如果服务启动失败则抛RuntimeException异常
*/
@SuppressWarnings("unchecked")
public <T extends SystemService> T startService(Class<T> serviceClass) {
// 获取服务类的类名
final String name = serviceClass.getName();
Slog.i(TAG, "Starting " + name);
// 判断服务类是否是SystemService的子类
if (!SystemService.class.isAssignableFrom(serviceClass)) {
throw new RuntimeException("Failed to create " + name
+ ": service must extend " + SystemService.class.getName());
}
final T service;
try {
// 获取服务类包含一个Context参数的构造方法
Constructor<T> constructor = serviceClass.getConstructor(Context.class);
// 创建这个服务类的实例
service = constructor.newInstance(mContext);
} catch (InstantiationException ex) {
throw new RuntimeException("Failed to create service " + name
+ ": service could not be instantiated", ex);
} catch (IllegalAccessException ex) {
throw new RuntimeException("Failed to create service " + name
+ ": service must have a public constructor with a Context argument", ex);
} catch (NoSuchMethodException ex) {
throw new RuntimeException("Failed to create service " + name
+ ": service must have a public constructor with a Context argument", ex);
} catch (InvocationTargetException ex) {
throw new RuntimeException("Failed to create service " + name
+ ": service constructor threw an exception", ex);
}
// 把服务添加到mServices列表中,方便后续使用时取出
mServices.add(service);
try {
// 回调服务的onStart方法
service.onStart();
} catch (RuntimeException ex) {
throw new RuntimeException("Failed to start service " + name
+ ": onStart threw an exception", ex);
}
return service;
}
在开启AlarmManagerService服务时,会创建服务的实例,看下该服务的创建过程:
final AlarmHandler mHandler = new AlarmHandler();
final Constants mConstants;
public AlarmManagerService(Context context) {
super(context);
// 初始化Handler和常量Constants类
mConstants = new Constants(mHandler);
}
初始化Handler的代码后面调用时再分析,这里先看下常量类的实现:
/**
* 该类中所有的时间单位都是毫秒。
* 这些常量保持与系统全局设置一致。
* 任何访问该类或该类中的字段都要持有AlarmManagerService.mLock锁
*/
private final class Constants extends ContentObserver {
// 在设置中保存的键值
private static final String KEY_MIN_FUTURITY = "min_futurity";
private static final String KEY_MIN_INTERVAL = "min_interval";
private static final String KEY_ALLOW_WHILE_IDLE_SHORT_TIME = "allow_while_idle_short_time";
private static final String KEY_ALLOW_WHILE_IDLE_LONG_TIME = "allow_while_idle_long_time";
private static final String KEY_ALLOW_WHILE_IDLE_WHITELIST_DURATION
= "allow_while_idle_whitelist_duration";
private static final long DEFAULT_MIN_FUTURITY = 5 * 1000;
private static final long DEFAULT_MIN_INTERVAL = 60 * 1000;
private static final long DEFAULT_ALLOW_WHILE_IDLE_SHORT_TIME = DEFAULT_MIN_FUTURITY;
private static final long DEFAULT_ALLOW_WHILE_IDLE_LONG_TIME = 9*60*1000;
private static final long DEFAULT_ALLOW_WHILE_IDLE_WHITELIST_DURATION = 10*1000;
// Minimum futurity of a new alarm
public long MIN_FUTURITY = DEFAULT_MIN_FUTURITY;
// Minimum alarm recurrence interval
public long MIN_INTERVAL = DEFAULT_MIN_INTERVAL;
// 从系统非空闲状态到可以执行flag为ALLOW_WHILE_IDLE的alarm的最小时间间隔:5秒钟
public long ALLOW_WHILE_IDLE_SHORT_TIME = DEFAULT_ALLOW_WHILE_IDLE_SHORT_TIME;
// 从系统空闲状态到可以执行flag为ALLOW_WHILE_IDLE的alarm的最小时间间隔:9分钟
public long ALLOW_WHILE_IDLE_LONG_TIME = DEFAULT_ALLOW_WHILE_IDLE_LONG_TIME;
// BroadcastOptions.setTemporaryAppWhitelistDuration() to use for FLAG_ALLOW_WHILE_IDLE.
public long ALLOW_WHILE_IDLE_WHITELIST_DURATION
= DEFAULT_ALLOW_WHILE_IDLE_WHITELIST_DURATION;
private ContentResolver mResolver;
private final KeyValueListParser mParser = new KeyValueListParser(',');
private long mLastAllowWhileIdleWhitelistDuration = -1;
public Constants(Handler handler) {
super(handler);
// 更新可以开始执行flag为ALLOW_WHILE_IDLE的alarm的最小时间间隔
updateAllowWhileIdleMinTimeLocked();
updateAllowWhileIdleWhitelistDurationLocked();
}
// 系统启动后会调用该方法,注册数据库监听
public void start(ContentResolver resolver) {
mResolver = resolver;
// 监听数据库变化
mResolver.registerContentObserver(Settings.Global.getUriFor(
Settings.Global.ALARM_MANAGER_CONSTANTS), false, this);
updateConstants();
}
// 更新可以开始执行flag为ALLOW_WHILE_IDLE的alarm的最小时间间隔
public void updateAllowWhileIdleMinTimeLocked() {
mAllowWhileIdleMinTime = mPendingIdleUntil != null
? ALLOW_WHILE_IDLE_LONG_TIME : ALLOW_WHILE_IDLE_SHORT_TIME;
}
public void updateAllowWhileIdleWhitelistDurationLocked() {
if (mLastAllowWhileIdleWhitelistDuration != ALLOW_WHILE_IDLE_WHITELIST_DURATION) {
mLastAllowWhileIdleWhitelistDuration = ALLOW_WHILE_IDLE_WHITELIST_DURATION;
BroadcastOptions opts = BroadcastOptions.makeBasic();
opts.setTemporaryAppWhitelistDuration(ALLOW_WHILE_IDLE_WHITELIST_DURATION);
mIdleOptions = opts.toBundle();
}
}
@Override
public void onChange(boolean selfChange, Uri uri) {
// 数据库内容变化时,更新一些本地变量
updateConstants();
}
. . .
}
看下AlarmManagerService类的onStart方法:
long mNativeData;
// 下一个包含wakeup的batch的start时间
private long mNextWakeup;
// 下一个包含Rtc wakeup的batch的start时间
private long mNextRtcWakeup;
// 下一个非wakeup的batch的start时间
private long mNextNonWakeup;
static final String TIMEZONE_PROPERTY = "persist.sys.timezone";
PowerManager.WakeLock mWakeLock;
// 时间变化发送者
PendingIntent mTimeTickSender;
// 日期变化发送者
PendingIntent mDateChangeSender;
// 时间变化的广播接收者
ClockReceiver mClockReceiver;
// 监听息屏/亮屏的广播接收者
InteractiveStateReceiver mInteractiveStateReceiver;
// 监听卸载的广播接收者
private UninstallReceiver mUninstallReceiver;
@Override
public void onStart() {
// 通过JNI对mNativeData进行初始化操作:
// 打开设备驱动"/dev/alarm"返回一个long型的与fd文件描述符有关的值
mNativeData = init();
mNextWakeup = mNextRtcWakeup = mNextNonWakeup = 0;
// 把当前时区信息保存到内核
setTimeZoneImpl(SystemProperties.get(TIMEZONE_PROPERTY));
// 初始化wakelock
PowerManager pm = (PowerManager) getContext().getSystemService(Context.POWER_SERVICE);
mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "*alarm*");
// 初始化时间变化的广播发送者,因为这里的接收者是ALL,所以所有的应用程序收到的ACTION_TIME_TICK广播都是这里发送的
mTimeTickSender = PendingIntent.getBroadcastAsUser(getContext(), 0,
new Intent(Intent.ACTION_TIME_TICK).addFlags(
Intent.FLAG_RECEIVER_REGISTERED_ONLY
| Intent.FLAG_RECEIVER_FOREGROUND), 0,
UserHandle.ALL);
// 初始化mDateChangeSender
Intent intent = new Intent(Intent.ACTION_DATE_CHANGED);
intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
mDateChangeSender = PendingIntent.getBroadcastAsUser(getContext(), 0, intent,
Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT, UserHandle.ALL);
// 初始化驱动来调度alarm
// 注册时间/日期变化广播接收者
mClockReceiver = new ClockReceiver();
// 调度时间变化事件,第一次发送时间变化广播,实现:在当前时间延迟一分钟后发送
// 在ClockReceiver的onReceive方法中接收到时间变化的广博就会调用
// scheduleTimeTickEvent方法发送一分钟后的广播
mClockReceiver.scheduleTimeTickEvent();
// 调度日期变化事件,每天0点发送一次广播
mClockReceiver.scheduleDateChangedEvent();
// 初始化监听息屏/亮屏的广播接收者
mInteractiveStateReceiver = new InteractiveStateReceiver();
// 监听应用卸载和SD卡不可用的广播,判断是否移除alarm
mUninstallReceiver = new UninstallReceiver();
if (mNativeData != 0) {
// 初始化AlarmThread并运行它的run方法
AlarmThread waitThread = new AlarmThread();
waitThread.start();
} else {
Slog.w(TAG, "Failed to open alarm driver. Falling back to a handler.");
}
// 发布服务
publishBinderService(Context.ALARM_SERVICE, mService);
}
private native long init();
// 把当前时区保存到内核
void setTimeZoneImpl(String tz) {
if (TextUtils.isEmpty(tz)) {
return;
}
// 获取要保存的时区
TimeZone zone = TimeZone.getTimeZone(tz);
// 写入时区时,避免同时写
boolean timeZoneWasChanged = false;
synchronized (this) {
// 再次获取要保存的时区
String current = SystemProperties.get(TIMEZONE_PROPERTY);
// 如果两次获取的时区不一致则说明时区发生变化,并重新把当前时区保存到设置中
if (current == null || !current.equals(zone.getID())) {
if (localLOGV) {
Slog.v(TAG, "timezone changed: " + current + ", new=" + zone.getID());
}
timeZoneWasChanged = true;
SystemProperties.set(TIMEZONE_PROPERTY, zone.getID());
}
// Update the kernel timezone information
// Kernel tracks time offsets as 'minutes west of GMT'
// 更新内核时区信息
// 内核跟踪时间偏移为GMT以西的分钟数
int gmtOffset = zone.getOffset(System.currentTimeMillis());
// 保存时区到内核
setKernelTimezone(mNativeData, -(gmtOffset / 60000));
}
TimeZone.setDefault(null);
// 如果时区发生改变则发送时区改变的广播
if (timeZoneWasChanged) {
Intent intent = new Intent(Intent.ACTION_TIMEZONE_CHANGED);
intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
intent.putExtra("time-zone", zone.getID());
getContext().sendBroadcastAsUser(intent, UserHandle.ALL);
}
}
// 保存时区信息到内核中
private native int setKernelTimezone(long nativeData, int minuteswest);
// 时间/日期变化广播接收者
class ClockReceiver extends BroadcastReceiver {
public ClockReceiver() {
// 注册时间/日期变化的广播接收者
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_TIME_TICK);
filter.addAction(Intent.ACTION_DATE_CHANGED);
getContext().registerReceiver(this, filter);
}
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(Intent.ACTION_TIME_TICK)) {
if (DEBUG_BATCH) {
Slog.v(TAG, "Received TIME_TICK alarm; rescheduling");
}
// 收到时间变化的广播,发送时间变化的广播给所有的接收者
scheduleTimeTickEvent();
} else if (intent.getAction().equals(Intent.ACTION_DATE_CHANGED)) {
// 由于内核不跟踪DST时间,所以需要在每天开始时,基于当前时区的gmt偏移 + 用户空间跟踪保存的信息来重置时区信息
TimeZone zone = TimeZone.getTimeZone(SystemProperties.get(TIMEZONE_PROPERTY));
int gmtOffset = zone.getOffset(System.currentTimeMillis());
// 日期变化时更新内核保存的时区信息
setKernelTimezone(mNativeData, -(gmtOffset / 60000));
// 调度日期变化事件
scheduleDateChangedEvent();
}
}
// 一分钟后给所有接收ACTION_TIME_TICK广播的接收者发送广播
public void scheduleTimeTickEvent() {
final long currentTime = System.currentTimeMillis();
final long nextTime = 60000 * ((currentTime / 60000) + 1);
// 下一次执行事件的延迟时间
final long tickEventDelay = nextTime - currentTime;
final WorkSource workSource = null; // Let system take blame for time tick events.
// 调用setImpl方法设置给所有接收ACTION_TIME_TICK广播的接收者发送广播
setImpl(ELAPSED_REALTIME, SystemClock.elapsedRealtime() + tickEventDelay, 0,
0, mTimeTickSender, AlarmManager.FLAG_STANDALONE, workSource, null,
Process.myUid());
}
// 调度日期变化事件
public void scheduleDateChangedEvent() {
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
calendar.set(Calendar.HOUR, 0);
calendar.set(Calendar.MINUTE, 0);
calendar.set(Calendar.SECOND, 0);
calendar.set(Calendar.MILLISECOND, 0);
calendar.add(Calendar.DAY_OF_MONTH, 1);
final WorkSource workSource = null; // Let system take blame for date change events.
// 设置mDateChangeSender
setImpl(RTC, calendar.getTimeInMillis(), 0, 0, mDateChangeSender,
AlarmManager.FLAG_STANDALONE, workSource, null, Process.myUid());
}
}
// 修正参数并设置传递过来的PendingIntent
void setImpl(int type, long triggerAtTime, long windowLength, long interval,
PendingIntent operation, int flags, WorkSource workSource,
AlarmManager.AlarmClockInfo alarmClock, int callingUid) {
if (operation == null) {
Slog.w(TAG, "set/setRepeating ignored because there is no intent");
return;
}
/*下面要修正传递过来的PendingIntent各相关参数了,所以可以在这里增加对alarm的管控规则*/
// 检查时间窗长度,如果超过半天就转换成一小时。
if (windowLength > AlarmManager.INTERVAL_HALF_DAY) {
Slog.w(TAG, "Window length " + windowLength
+ "ms suspiciously long; limiting to 1 hour");
windowLength = AlarmManager.INTERVAL_HOUR;
}
// 检查alarm的执行周期,如果alarm的执行周期小于1分钟,则转换为1分钟。
// 从这里可以得知周期性alarm的最小有效周期为1分钟,若要执行周期小于1分钟的事,不能使用alarm实现
final long minInterval = mConstants.MIN_INTERVAL;// 1分钟
if (interval > 0 && interval < minInterval) {
Slog.w(TAG, "Suspiciously short interval " + interval
+ " millis; expanding to " + (minInterval/1000)
+ " seconds");
interval = minInterval;
}
// 检查type的合法性
if (type < RTC_WAKEUP || type > RTC_POWEROFF_WAKEUP) {
throw n